package NW_Dynamic;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import NWPackage.OneSettingDistMatrix;
import NWPackage.RankDist;

public class DynamicHelper {
	
	
	public static double CalcEntropyOfVectors(
			HashMap<String, RankDist> allProbsIsWinner) {
		
		double sum = 0.0;
		for (String cand : allProbsIsWinner.keySet()) {
			sum += allProbsIsWinner.get(cand).getEntropyOfVector();
		}
		return sum;
	}
	
	public static void CalcCandidateProbForWinning(
			HashMap<String, RankDist> allProbsIsWinner,
			HashMap<String, RankDist> allProbsMost,
			HashMap<String, RankDist> allProbsEqual, int numberOfVotes,
			Set<String> voters, List<String> optionalWinners) {

		for (String cand : optionalWinners) {
			int candIndex = optionalWinners.indexOf(cand);
			RankDist probs = new RankDist();
			//RankDist equalProbs = allProbsEqual.get(cand);
			//RankDist cumulativeProbs = allProbsMost.get(cand);
			if (allProbsEqual.containsKey(cand)){
				for (int vote = 1; vote <= numberOfVotes*voters.size(); vote++) {
					probs.addRank(vote, CalcWinningProbForVote(vote,cand,candIndex,allProbsMost,allProbsEqual,optionalWinners) );
				}
				allProbsIsWinner.put(cand, probs);
			}
		}
		
	}
	
	private static double CalcWinningProbForVote(int vote, String cand,int candIndex, HashMap<String, RankDist> allProbsMost, HashMap<String, RankDist> allProbsEqual, List<String> optionalWinners) {
		
		try{
			double duplicate = allProbsEqual.get(cand).getVoteProb(vote);
			
			//for each candidate other than this one, duplicate his probability for "MOST S" with this probability
			//if the other candidate is smaller by lexi order - get his probability for MOST (vote-1)
			for (int nextCandIndex = 0; nextCandIndex < optionalWinners.size(); nextCandIndex++) {
				String nextCandidate = optionalWinners.get(nextCandIndex) ;
				
				//check if it is not the same candidate we are calculating
				if (nextCandidate != cand)
				{
					//if this candidate is first in lexi order - calc his (vote-1) prob
					if (nextCandidate.compareTo(cand) < 0)
					{
						duplicate = duplicate * allProbsMost.get(nextCandidate).getVoteProb(vote-1);
					}
					//else we can calc his vote because of tie breaks!
					else
					{
						duplicate = duplicate * allProbsMost.get(nextCandidate).getVoteProb(vote);
					}
				}
			}
			return duplicate;
		}
		catch(Exception ex) { return 0.0;}
	}
	
	public static void CalcCandidateVoteCumulative(HashMap<String, RankDist> allProbsMost,HashMap<String, RankDist> allProbsEqual,int numberOfVotes,Set<String> voters) {
		for (String cand : allProbsEqual.keySet()) {
			double cumulativeProb = 0.0;
			RankDist probs = new RankDist();
			RankDist equalProbs = allProbsEqual.get(cand);
			for (int vote = 1; vote <= numberOfVotes*voters.size(); vote++) {
				double equalVote = equalProbs.getVoteProb(vote);
				probs.addRank(vote, equalVote+cumulativeProb);
				cumulativeProb+=equalVote;
			}
			allProbsMost.put(cand, probs);
		}
		
	}
	
	public static void CalcCandidateVoteProbability(OneSettingDistMatrix osdmTempIteration,List<String> optionalWinners, int numberOfVotes,Set<String> voters, HashMap<String, RankDist> allProbsEqual) {
		for (String cand : optionalWinners) {
			RankDist probs = new RankDist();
			for (int i = 1; i <= numberOfVotes*voters.size(); i++) {
				double voteProb = CalcVoteProb(voters,cand,numberOfVotes,numberOfVotes,i,osdmTempIteration);
				probs.addRank(i, voteProb);
			}
			allProbsEqual.put(cand, probs);
		}
	}
	
	private static double CalcVoteProb(Set<String> voters, String candidate,int maxfVotes, int vote, int sumOfVotes, OneSettingDistMatrix osdmTempIteration) {
		if (voters.size() == 1)
		{
			String voterName = voters.iterator().next();
			return osdmTempIteration.getVoteProb(voterName, candidate, sumOfVotes);
		}
		else if (vote < 1 || sumOfVotes < voters.size())
			return 0.0;
		else{
			double ans=0.0;
			vote = maxfVotes;
			Iterator<String> it = voters.iterator();
			
			String voterName = it.next();
			Set<String> nextVoters = new HashSet<String>();
			nextVoters.addAll(voters);
			nextVoters.remove(voterName);
			
			while(vote>0){
				ans += ( osdmTempIteration.getVoteProb(voterName, candidate, vote)* CalcVoteProb(nextVoters,candidate,maxfVotes,vote,sumOfVotes-vote,osdmTempIteration));

				vote--;
			}
			return ans;
		}	
		
	}
}
